from image_utils import logging # 从image_utils.py中导入logging对象
import numpy as np


def adjust_brightness(image, brightness_factor):
    """
    调整图像亮度
    :param image: 输入图像，numpy数组
    :param brightness_factor: 亮度调节因子(0.0-2.0)
    :return: 调整后的图像
    """
    try:
        logging.info(f"开始调整图像亮度，亮度因子: {brightness_factor}")
        
        # 确保亮度因子在合理范围内
        brightness_factor = max(0.0, min(2.0, brightness_factor))
        
        # 转换图像数据类型为float32以避免溢出
        image_float = image.astype(np.float32)
        
        # 应用亮度调整
        adjusted_image = image_float * brightness_factor
        
        # 确保像素值在0-255范围内
        adjusted_image = np.clip(adjusted_image, 0, 255)
        
        # 转换回原始数据类型
        return adjusted_image.astype(image.dtype)
    except Exception as e:
        raise ValueError(f"Error occurred while adjusting brightness: {e}")


def global_threshold(image, threshold):
    """
    全局阈值处理
    :param image: 输入灰度图像，numpy数组
    :param threshold: 阈值(0-255)
    :return: 二值化图像
    """
    try:
        logging.info(f"开始全局阈值处理，阈值: {threshold}")
        
        # 确保图像是灰度图
        if len(image.shape) != 2:
            raise ValueError("全局阈值处理只能在灰度图上使用")
            
        # 确保阈值在合理范围内
        threshold = max(0, min(255, threshold))
        
        # 应用阈值处理
        binary_image = np.where(image > threshold, 255, 0)
        
        return binary_image.astype(np.uint8)
    except Exception as e:
        raise ValueError(f"Error occurred during global thresholding: {e}")


def moving_difference(image, shift):
    """
    移动差分边缘检测
    :param image: 输入灰度图像，numpy数组
    :param shift: 平移像素数(-3到3)
    :return: 边缘差分图像
    """
    try:
        logging.info(f"开始移动差分边缘检测，平移像素: {shift}")
        
        # 确保图像是灰度图
        if len(image.shape) != 2:
            raise ValueError("移动差分只能在灰度图上使用")
            
        # 确保平移量在合理范围内
        shift = max(-3, min(3, shift))
        
        if shift == 0:
            return np.zeros_like(image)
            
        # 创建平移后的图像
        shifted = np.roll(image, shift, axis=1)
        
        # 计算差分并取绝对值
        diff = np.abs(image.astype(np.int16) - shifted.astype(np.int16))
        
        # 归一化到0-255范围
        diff = (diff * (255.0 / diff.max())).astype(np.uint8)
        
        return diff
    except Exception as e:
        raise ValueError(f"Error occurred during moving difference: {e}")


def crop_image(image, crop_region):
    """
    裁剪图像
    :param image: 输入图像，PIL.Image对象
    :param crop_region: 裁剪区域,格式为(上,下,左,右)
    :return: 裁剪后的图像
    """
    try:
        logging.info(f"开始裁剪图像，裁剪区域,{crop_region}")
        

        # 从crop_region中提取上、下、左、右的坐标
        top, bottom, left, right = crop_region
        
        # 直接使用切片操作，裁剪图像 image 生成裁剪后的图像 cropped_image
        cropped_image = image[top:bottom, left:right]

        return cropped_image
    except Exception as e:
        raise ValueError(f"Error occurred while cropping image: {e}")


def generate_color_mask(image, color):
    """
    生成颜色掩模
    :param image: 输入图像，numpy数组
    :param color: 颜色类型 ('red', 'green', 'blue')
    :return: 颜色掩模图像(单通道，与原图同尺寸)
    """
    try:
        logging.info(f"开始生成{color}掩模")
        
        if len(image.shape) != 3 or image.shape[2] != 3:
            raise ValueError("输入图像必须是RGB彩色图像")
            
        # 创建单通道掩模(确保与原图同尺寸)
        height, width = image.shape[:2]
        mask = np.zeros((height, width), dtype=np.uint8)
        
        # 根据颜色通道生成掩模
        if color == 'red':
            mask[(image[:,:,0] > 200) & (image[:,:,1] < 100) & (image[:,:,2] < 100)] = 255
        elif color == 'green':
            mask[(image[:,:,1] > 200) & (image[:,:,0] < 100) & (image[:,:,2] < 100)] = 255
        elif color == 'blue':
            mask[(image[:,:,2] > 200) & (image[:,:,0] < 100) & (image[:,:,1] < 100)] = 255
        else:
            raise ValueError("不支持的掩模颜色")
            
        # 验证输出尺寸
        assert mask.shape == image.shape[:2], f"掩模尺寸{mask.shape}与原图尺寸{image.shape[:2]}不匹配"
        return mask
    except Exception as e:
        raise ValueError(f"生成{color}掩模时出错: {e}")


def apply_mask(image, mask, operation='and'):
    """
    应用掩模运算
    :param image: 输入图像，numpy数组
    :param mask: 掩模图像(单通道)，numpy数组
    :param operation: 运算类型 ('and', 'not', 'or', 'xor')
    :return: 运算结果图像(保持原图尺寸)
    """
    try:
        logging.info(f"开始应用{operation}掩模运算")
        
        if image.shape[:2] != mask.shape:
            # 自动调整掩模尺寸匹配原图
            mask = cv2.resize(mask, (image.shape[1], image.shape[0]))
            _, binary_mask = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
        else:
            _, binary_mask = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
        
        # 初始化结果图像(确保尺寸一致)
        result = np.zeros_like(image)
        
        # 应用不同的掩模运算
        if operation == 'and':
            # 保留掩模区域的原图内容
            masked = cv2.bitwise_and(image, image, mask=binary_mask)
            result = np.where(cv2.merge([binary_mask]*3), masked, [255, 255, 255])
        elif operation == 'not':
            # 保留非掩模区域的原图内容
            inverted_mask = cv2.bitwise_not(binary_mask)
            masked = cv2.bitwise_and(image, image, mask=inverted_mask)
            result = np.where(cv2.merge([inverted_mask]*3), masked, [255, 255, 255])
        elif operation == 'or':
            result = cv2.bitwise_or(image, cv2.merge([binary_mask]*3))
        elif operation == 'xor':
            result = cv2.bitwise_xor(image, cv2.merge([binary_mask]*3))
        else:
            raise ValueError("不支持的掩模运算类型")
            
        # 确保输出尺寸与输入一致
        assert result.shape == image.shape, "输出图像尺寸与输入不一致"
        return result
    except Exception as e:
        raise ValueError(f"应用{operation}掩模运算时出错: {e}")
    
